package com.example.design.threadpool;

import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @Description 固定大小线程池会有饥饿现象 -> 线程数量不足，不是死锁哦；带缓冲线程池是不会有饥饿现象的
 * @date 2023/12/27 9:33
 * @Author liuzhihui
 * @Version 1.0
 */
@Slf4j
public class ThreadPoolHungry {
    public static void main(String[] args) {
        /**
         * 问题触发
         */
//        // 如果线程数小于等于父任务数，那么就会导致线程池线程被用完，导致只有父任务被执行，子任务执行不了
//        ExecutorService executorService = Executors.newFixedThreadPool(1);
//        // 两个客人
//        executorService.execute(new Task1(executorService));
//        executorService.execute(new Task1(executorService));

        /**
         * 问题解决：两个任务使用不同的线程池就行
         */
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        ExecutorService executorService2 = Executors.newFixedThreadPool(1);
        executorService.execute(new Task1(executorService2));
        executorService.execute(new Task1(executorService2));
    }

    /**
     * 父任务：点餐
     */
    @Data
    public static class Task1 implements Runnable {
        ExecutorService executorService;

        public Task1(ExecutorService executorService) {
            this.executorService = executorService;
        }

        @SneakyThrows
        @Override
        public void run() {
            // 执行任务一
            log.debug("任务一：点餐....");

            // 执行任务二
            Future submit = executorService.submit(new Task2());
            Object o = submit.get();
            log.debug("上菜：{}", o);
        }
    }

    /**
     * 子任务：做菜
     */
    @Data
    public static class Task2 implements Callable {
        @Override
        public Object call() throws Exception {
            log.debug("任务二：做菜....");
            Random random = new Random();
            return "蛋炒饭" + random.nextInt();
        }
    }


}
